package com.zwj.spring_study.a05.postprocessor;

import com.zwj.spring_study.a05.Config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Set;

/**
 * Bean工厂后置处理器：解析注解@Bean，被@Bean注解标识的方法返回的类加入到容器中
 *
 * @author 张文接
 * @version 1.0
 * @createTime 2024/6/10 22:08
 */
@Slf4j
public class AtBeanPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        try {
            //通过CachingMetadataReaderFactory 工厂类获取【元数据信息读取器-MetadataReader】
            CachingMetadataReaderFactory readerFactory = new CachingMetadataReaderFactory();
            MetadataReader metadataReader = readerFactory.getMetadataReader(Config.class.getName());
            log.info("className:{}", Config.class.getName());
            String configBeanName = configurableListableBeanFactory.getBean(Config.class).getClass().getName();
            log.info("在容器中config类的className：{}", configBeanName);
            Set<MethodMetadata> annotatedMethods = metadataReader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
            if (CollectionUtils.isEmpty(annotatedMethods)) {
                return;
            }
            //遍历被@Bean注解标识的方法元数据信息
            for (MethodMetadata annotatedMethod : annotatedMethods) {
                String initMethod = annotatedMethod.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
                String methodName = annotatedMethod.getMethodName();
                log.info("方法名字：{}", methodName);
                System.out.println(annotatedMethod);
                //获取beanDefinition
                BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition();
                beanDefinitionBuilder.setFactoryMethodOnBean(methodName, configBeanName);
                //设置自动注入的模式，在 @Bean 标识的方法有入参时，可以自动注入参数实例，默认为 AUTOWIRE_NO（不自动注入）
                //而对于构造方法和工厂方法的注入，都使用的是 AUTOWIRE_CONSTRUCTOR 模式
                beanDefinitionBuilder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
                if (!initMethod.isEmpty()) {
                    beanDefinitionBuilder.setInitMethodName(initMethod);
                }
                AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
                //注册到容器中
                if (configurableListableBeanFactory instanceof DefaultListableBeanFactory) {
                    DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
                    //注册
                    beanFactory.registerBeanDefinition(methodName, beanDefinition);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
